home *** CD-ROM | disk | FTP | other *** search
- /* ServiceMgr.c
- * Handle the Services menu in Writeswell, Jr.
- * ©1992 Working Software, Inc.
- * This source code is copyrighted. Permission is granted to use the Word Services
- * portion of the Writeswell Jr. source code in your own programs, but you
- * may not distribute the Writeswell Jr. word-processor code as a
- * commercial product. If you modify the code, please do not call it
- * Writeswell Jr. (or Writeswell.) This will ensure that people understand the
- * program and don’t have to deal with a number of different versions with
- * who-knows-what going on in the code.
- *
- * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
- * 19 Apr 92 Mike Crawford
- */
-
- #include <Aliases.h>
- #include <EPPC.h>
- #include <AppleEvents.h>
- #include <AEObjects.h>
- #include <AEPackObject.h>
- #include "AERegistry.h"
- #include "WordServices.h"
- #include "TestBed.h"
- #include "TBConstants.h"
- #include "AppEvents.h"
- #include "AEObj.h"
- #include "Gripe.h"
- #include "Prefs.h"
- #include "DoChecking.h"
- #include "ObText.h"
- #include "InitMenu.h"
- #include "ServiceMgr.h"
- #include "TBGlobals.h"
-
- OSErr GetNewBatchService( void )
- {
- AEAddressDesc spellerAddr;
- AEDesc stringDesc;
- AEDesc aliasDesc;
- AEDesc iconDesc;
- OSErr err;
-
- if ( CountServices() >= kMaxServices ){
- RealGripe( "\pNo more services may be added" );
- return noErr;
- }
-
- /* Look for a currently running speller */
-
- err = GetSpellerAddress( &spellerAddr );
- if ( err ){
- return ( err == userCanceledErr ? noErr : err );
- }
-
- /*****
- * Request the speller's batch menu string
- *****/
-
- err = GetAppProperty( &spellerAddr, pBatchMenuString, typePString, &stringDesc );
- if ( err ){
- Gripe( "\pGetAppProperty failed to get menu string" );
- return err;
- }
-
- /*DebugStr( *(stringDesc.dataHandle) );*/ /* Uncomment this to look at string */
-
-
- /*****
- * Request the speller's location alias
- *****/
-
- err = GetAppProperty( &spellerAddr, pLocation, typeAlias, &aliasDesc );
- if ( err ){
- Gripe( "\pGetAppProperty failed to get location alias" );
- return err;
- }
-
- /*
- pMenuIcon
- Description: The value of this property is a small icon that may be
- placed in the menu along with the interactive or batch
- menu strings. It should be identical to the small icon
- that the speller shows in the Finder. Word processors that
- take advantage of this can use it to make the different menu
- items more distinguishable (a user might have two different
- spelling checkers).
- Object Class ID: typePixelMap
- */
-
- iconDesc.dataHandle = (Handle)NULL;
- iconDesc.descriptorType = typeNull;
-
- err = GetAppProperty( &spellerAddr, pMenuIcon, typeSmallIcon, &iconDesc );
-
- /* It is permissible for the icon not to be present. We just won't display one.
- */
-
- if ( err && err != errAENoSuchObject ){
- Gripe( "\pGetAppProperty failed to get speller menu icon" );
- return err;
- }
-
- /* Save the information in the preferences file */
-
- err = SaveServiceInfo( kBatchService, stringDesc, aliasDesc, iconDesc );
- if ( err ){
- Gripe( "\pCould not save service info" );
- return err;
- }
-
- RebuildServiceMenu();
-
- err = AEDisposeDesc( &stringDesc );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AEDisposeDesc( &aliasDesc );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AEDisposeDesc( &iconDesc );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = AEDisposeDesc( &spellerAddr );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
- spellerAddr.descriptorType = typeNull;
- spellerAddr.dataHandle = (Handle)NULL;
-
- return noErr;
- }
-
- OSErr GetAppProperty( AEAddressDesc *spellerAddrPtr,
- DescType propCode,
- DescType desiredType,
- AEDesc *resultPtr )
- {
- AEDesc errDesc;
- AppleEvent getDataEvent;
- AppleEvent replyEvent;
- AEDesc nullDesc;
- AEDesc propSpec;
- AEDesc propDesc;
- OSErr err;
-
- /* Create the descriptor for the container (the application, or null) */
-
- err = AECreateDesc( typeNull, (Ptr)NULL, (Size)0, &nullDesc );
- if ( err )
- return err;
-
- /* Create the key data, which gives the code for the desired property */
-
- err = AECreateDesc( typeType, (Ptr)&propCode, sizeof( propCode ), &propDesc );
- if ( err )
- return err;
-
- /* Create the Object Specifier for the menu string property */
-
- err = CreateObjSpecifier( typeProperty,
- &nullDesc,
- formPropertyID,
- &propDesc,
- true, /* Dispose of input descriptors */
- &propSpec );
- if ( err )
- return err;
-
- /* Create the event to send to the speller */
-
- err = AECreateAppleEvent( kAECoreSuite,
- kAEGetData,
- spellerAddrPtr,
- kAutoGenerateReturnID,
- kAnyTransactionID,
- &getDataEvent );
-
- if ( err ){
- Gripe( "\pcreate getd event failed" );
- return err;
- }
-
- /* Insert the object specifier as the direct object of the batch event */
-
- err = AEPutParamDesc( &getDataEvent,
- keyDirectObject,
- &propSpec );
- if ( err ){
- Gripe( "\pAEPutParamDesc failed to put direct object on Get Data event" );
- return err;
- }
- err = AEDisposeDesc( &propSpec );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* Send the event. We await the reply, so that if there is a failure of some
- * sort in the initial connection, we can alert the user right away. The timeout
- * value to use here should be as long as one would care to have a user wait for
- * the completion of a menu command. Since we expect that the speller is on a local
- * machine in this case, and should be able to respond immediately, we just give
- * a few seconds for the timeout.
- *
- * We should assign an idle proc to spin the cursor. Even better would be a progress
- * dialog that says "Contacting speller" or some such, with an animated display that
- * shows the time elapsed relative to the total timeout, so the user will know how
- * long she may have to wait
- */
-
- #define kFewSeconds 300
-
- err = AESend( &getDataEvent,
- &replyEvent,
- kAEWaitReply + kAENeverInteract,
- kAENormalPriority,
- kFewSeconds,
- (AEIdleUPP)NULL,
- (AEFilterUPP)NULL );
-
- if ( err ){
- Gripe( "\psend getd event failed" );
- return err;
- }
- err = AEDisposeDesc( &getDataEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- /* At this point we have received the client's reply event. Check for an error
- * result.
- */
-
- err = AEGetParamDesc( &replyEvent,
- keyErrorNumber,
- typeShortInteger,
- &errDesc );
-
- if ( err == errAEDescNotFound ){
- /* There is no error value - get the data from the reply event.
- * This will call our coercion routine to convert the text to a Pascal string -
- * the data is actually either typeIntlText or typeChar.
- */
-
- err = AEGetParamDesc( &replyEvent,
- keyDirectObject,
- desiredType,
- resultPtr );
- if ( err ){
- Gripe( "\pCannot get reply value" );
- return err;
- }
-
- /* MDC 1.1.1 */
-
- err = AEDisposeDesc( &replyEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- } else {
- err = AEDisposeDesc( &replyEvent );
- if ( err ){
- Gripe( "\pAEDisposeDesc failed" );
- return err;
- }
-
- err = **(short**)(errDesc.dataHandle);
- /* err = */ AEDisposeDesc( &propSpec );
-
- if ( err ){
- if ( err == errAENoSuchObject )
- return err; /* This is an OK error */
- else{
- Gripe( "\pError result returned from speller" );
- return err;
- }
- }
- }
-
- return noErr;
- }
- void RebuildServiceMenu( void )
- {
- MenuHandle servMenu;
- short numItems;
- short i;
-
- servMenu = GetServiceMenu();
- if ( !servMenu ){
- Gripe( "\pCannot get service menu handle" );
- return;
- }
-
- numItems = CountMItems( servMenu );
-
- for ( i = numItems; i > kSMDash; i-- ){
- DelMenuItem( servMenu, i );
- }
-
- BuildServiceMenu();
-
- return;
- }
-
- OSErr GetSpellerAddress( AEAddressDesc *spellerAddrPtr )
- {
- PortInfoRec portInfo;
- TargetID targetID;
- OSErr err;
-
- err = GetTargetAddress( (StringPtr)"\pChoose a Word Services Server",
- (StringPtr)"\pApple Event Aware Programs",
- &portInfo,
- spellerAddrPtr,
- (StringPtr)"\pWORDSERVICES",
- &targetID );
- return err;
- }
-
- short CountServices( void )
- {
- WWJrPrefsHdl prefHdl;
- short i;
- short count;
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get preferences handle" );
- return kMaxServices;
- }
-
- count = 0;
-
- for ( i = 0; i < kMaxServices; i++ ){
- if ( (*prefHdl)->serviceType[ i ] != kNoService )
- count++;
- }
-
- return count;
- }
-
- short GetServiceSlot( void )
- {
- WWJrPrefsHdl prefHdl;
- short i;
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get preferences handle" );
- return kMaxServices;
- }
-
- for ( i = 0; i < kMaxServices; i++ ){
- if ( (*prefHdl)->serviceType[ i ] == kNoService )
- return i;
- }
-
- return kMaxServices; /* No Free slots */
- }
-
- OSErr SaveServiceInfo( ServiceType serviceType,
- AEDesc menuDesc,
- AEDesc aliasDesc,
- AEDesc iconDesc )
- {
- short slot;
- WWJrPrefsHdl prefHdl;
- short resID;
- short iconResID;
- Handle resHandle;
- short curFile;
- OSErr err;
-
- slot = GetServiceSlot();
-
- if ( slot == kMaxServices ){
- Gripe( "\pOut of slots for new services" );
- return ioErr; /* Not sure what a good error would be */
- }
-
- prefHdl = GetPrefHandle();
- if ( !prefHdl ){
- Gripe( "\pCannot get preferences handle" );
- return resNotFound;
- }
-
- resID = kServiceBaseID + slot;
-
- curFile = CurResFile();
- UseResFile( gPrefFileRefNum );
-
- /* Make sure there's no old resources around... there shouldn't be */
-
- resHandle = GetResource( 'STR ', resID );
- if ( resHandle )
- RmveResource( resHandle );
-
- resHandle = GetResource( rAliasType, resID );
- if ( resHandle )
- RmveResource( resHandle );
-
- /* Copy the string into the resource file */
-
- resHandle = menuDesc.dataHandle;
-
- err = HandToHand( &resHandle );
- if ( err ){
- UseResFile( curFile );
- return err;
- }
-
- AddResource( resHandle, 'STR ', resID, "\p" );
- err = ResError();
- if ( err ){
- DisposHandle( resHandle );
- UseResFile( curFile );
- return err;
- }
- WriteResource( resHandle );
-
- /* Copy the alias record into the resource file */
-
- resHandle = aliasDesc.dataHandle;
-
- err = HandToHand( &resHandle );
- if ( err ){
- UseResFile( curFile );
- return err;
- }
-
- AddResource( resHandle, rAliasType, resID, "\p" ); /* rAliasType is 'alis' */
- err = ResError();
- if ( err ){
- DisposHandle( resHandle );
- UseResFile( curFile );
- return err;
- }
- WriteResource( resHandle );
-
- /* Copy the menu icon into the resource file */
-
- resHandle = iconDesc.dataHandle;
-
- if ( iconDesc.descriptorType != typeNull && resHandle != (Handle)NULL ){
-
- err = HandToHand( &resHandle );
- if ( err ){
- UseResFile( curFile );
- return err;
- }
-
- iconResID = kMenuIconBaseID + slot;
-
- AddResource( resHandle, 'SICN', iconResID, "\p" );
- err = ResError();
- if ( err ){
- DisposHandle( resHandle );
- UseResFile( curFile );
- return err;
- }
- WriteResource( resHandle );
- }
-
- (*prefHdl)->serviceType[ slot ] = serviceType;
-
- ChangedResource( (Handle) prefHdl );
- WriteResource( (Handle) prefHdl );
-
- UseResFile( curFile );
-
- return noErr;
- }